package model.tokens;

import java.util.Arrays;
import java.util.Stack;

import model.semantics.Node;
import model.semantics.Operation;
import model.semantics.OperatorNode;

import model.parser.ParserException;

import util.resources.ResourceManager;
import util.reflection.Reflection;

/**
 * A functional tokens 
 */

public abstract class FunctionalToken<T> extends NodeToken<T>{
	private String myClassName;
	private int myOrder;
	private int myPrecedence;
	private String[] myCallArgs;
	private static NodeFactory nodeFactory;
	
	public int getOrder(){
		return myOrder;
	}
	
	public int getPrecedence(){
		return myPrecedence;
	}
	
	public String getClassName(){
		return myClassName;
	}
	
	public FunctionalToken(String symbol, String syntaxFileName) {
		super(symbol);
		if(nodeFactory == null) {
			nodeFactory = new NodeFactory();
		}
		
		ResourceManager resources = ResourceManager.getInstance();
		resources.addResourcesFromFile(syntaxFileName);
		String[] params = resources.getStringArray(symbol);
		
		// Throw an exception if we were unable to match this symbol to a token type.
		if(params == null) {
			throw ParserException.BAD_TOKEN;
		}
		
		myOrder = Integer.parseInt(params[0]);
		myPrecedence = Integer.parseInt(params[1]);
		myClassName = params[2];
		myCallArgs = Arrays.copyOfRange(params, 3, params.length);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public Node<T> makeNewInstance(Stack<Node<T>> stack) {
		int argSize;
		// Handle multi-argument functions.
		if(myOrder < 0) argSize = stack.size();
		else argSize = myOrder;
		Node<T>[] values = new Node[argSize];
		for(int i = argSize-1; i >= 0; i--) {
			values[i] = stack.pop();
		}
		
		/* Create a new instance of the functional token by passing its order, call
		 * arguments, and kids. */
		Node<T> node = (Node<T>) Reflection.callMethod(nodeFactory, myClassName, myOrder,
				myCallArgs, values);
		return node;
	}
}
